package mysql8学习.高级.第15章_锁;

/**
 * 3.6其它锁之:死锁
 * 1.概念
 *      两个事务都持有对方需要的锁，并且在等待对方释放，并且双方都不会释放自己的锁。
 *
 * 2.产生死锁的必要条件
 *      1.两个或者两个以上事务
 *      2.每个事务都已经持有锁并且申请新的锁
 *      3.锁资源同时只能被同一个事务持有或者不兼容
 *      4.事务之间因为持有锁和申请锁导致彼此循环等待
 *
 * 死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
 *
 * 3.如何处理死锁
 * 方式1:等待，直到超时(innodb_lock_wait_timeout=50s)
 *
 * 方式2:使用死锁检测进行死锁处理，
 *      方式1检测死锁太过被动，innodb还提供了wait_for graph算法来主动进行死锁检测，
 *      每当加锁请求无法立即满足需要并进入等待时，wait-for graph算法都会被触发。
 *      这是一种较为主动的死锁检测机制”，
 *      要求数据库保存锁的信息链表和事务等待链表两部分信息。
 *      死锁检测的原理是构建一个以事务为顶点、 锁为边的有向图，判断有向图是否存在环，
 *      存在即有死锁。
 *      一旦检测到回路、有死锁，这时候InnoDB存储引擎会选择回滚undo量最小的事务，
 *      让其他事务继续执行(innodb_deadlock_detect=on 表示开启这个逻辑)。
 *
 *      缺点:每个新的被阻塞的线程，都要判断是不是由于自己的加入导致了死锁，
 *          这个操作时间复杂度是0(n)。如果100个并发线程同时更新同一行，
 *          意味着要检测100*100= 1万次，1万个线程就会有1千万次检测。
 *          如何解决?
 *          ●方式1:关闭死锁检测，但意味着可能会出现大量的超时，会导致业务有损。
 *          ●方式2:控制并发访问的数量。比如在中间件中实现对于相同行的更新，
 *            在进入引擎之前排队，这样在InnoDB内部就不会有大量的死锁检测工作。
 *      进一步的思路:
 *      可以考虑通过将一行改成逻辑上的多行来减少锁冲突。
 *      比如，连锁超市账户总额的记录，可以考虑放到多条记录上。
 *      账户总额等于这多个记录的值的总和。
 *
 * 4.如何避免死锁
 * ●合理设计索引，使业务SQL尽可能通过索引定位更少的行，减少锁竞争。
 * ●调整业务逻辑SQL执行顺序，避免 update/delete 长时间持有锁的SQL在事务前面。
 * ●避免大事务，尽量将大事务拆成多个小事务来处理，小事务缩短锁定资源的时间，
 *   发生锁冲突的几率也更小。
 * ●在并发比较高的系统中，不要显式加锁,特别是是在事务里显式加锁。
 *   如 select .. for update语句，如果是在
 *   事务里运行了start transaction或设置了autocommit等于0，
 *   那么就会锁定所查找到的记录。
 * ●降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择，
 * 比如将隔离级别从RR调整为RC，可以避免掉很多因为gap锁造成的死锁。
 *
 */
public class C_F_其他之死锁 {
}
